package com.gary.security.action;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

import net.sf.json.JSONException;

import org.apache.struts2.ServletActionContext;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gary.core.action.BaseAction;
import com.gary.core.orm.query.NullQueryItem;
import com.gary.core.orm.query.QueryFilter;
import com.gary.core.orm.utils.PageList;
import com.gary.core.util.BeanUtil;
import com.gary.core.util.JsonUtils;
import com.gary.security.facade.SecurityFacade;
import com.gary.security.model.MenuInfo;
import com.gary.security.model.RescInfo;
import com.gary.security.model.RoleInfo;
import com.gary.security.repository.RoleRepository;


/**
 * role action.
 *
 */
public class RoleAction extends BaseAction<RoleInfo> {
    /** * serial. */
    static final long serialVersionUID = 0L;

    /** logger. */
    private static Logger logger = LoggerFactory.getLogger(RoleAction.class);

    /** * role manager. */
    private transient RoleRepository roleReps = null;
    
    private SecurityFacade facade;

    /** * role list. */
    private List<RoleInfo> list;

    /** * resc list. */
    private List<RescInfo> rescList;

    /** * menu list. */
    private List<MenuInfo> menuList;

    /** * id. */
    private long id;

    /** * resc id. */
    private long rescId;

    /** * menu id. */
    private long menuId;

    // ====================================================
    private int start;
    private int limit;
    private String sort;
    private String dir;
    private String ids;
    private Long roleId;
    private boolean auth;

    /** * @return success. */
    public String list() {
        this.list = roleReps.getAll();

        return SUCCESS;
    }

    /** * @return forward. */
    public String edit() {
        this.model = roleReps.getById(id,true);

        return "forward";
    }

    /** * @return rescsByRole. */
    public String rescsByRole() {
        this.model = roleReps.getById(id,true);
        this.rescList = facade.getRescList(null);

        for (RescInfo resc : rescList) {
            if (model.getRescs().contains(resc)) {
                resc.setAuthorized(true);
            }
        }

        return "rescsByRole";
    }

    /** * @return auth resc end. */
    public String unauthResc() {
        RoleInfo role = roleReps.getById(id,false);
        RescInfo resc = facade.getRescById(rescId);

        if (role.getRescs().contains(resc)) {
            role.getRescs().remove(resc);
            roleReps.save(role);
        }

        return "auth-resc-end";
    }

    /** * @return menusByRole. */
    public String menusByRole() {
        this.model = roleReps.getById(id,false);
        this.menuList = facade.getMenuList(null);

        for (MenuInfo menu : menuList) {
            if (model.getMenus().contains(menu)) {
                menu.setChecked(true);
            }
        }

        return "menusByRole";
    }

    /** * @return auth menu end. */
    public String authMenu() {
        RoleInfo role = roleReps.getById(id,false);
        MenuInfo menu = facade.getMenuById(menuId);

        if (!role.getMenus().contains(menu)) {
            role.getMenus().add(menu);
            roleReps.save(role);
        }

        return "auth-menu-end";
    }

    /** * @return auth menu end. */
    public String unauthMenu() {
    	RoleInfo role = roleReps.getById(id,false);
        MenuInfo menu = facade.getMenuById(menuId);

        if (role.getMenus().contains(menu)) {
            role.getMenus().remove(menu);
            roleReps.save(role);
        }

        return "auth-menu-end";
    }

    //
    /** * @param roleManager role manager. */
    public void setRoleReps(RoleRepository roleReps) {
        this.roleReps = roleReps;
    }

    /** * @return role list. */
    public List<RoleInfo> getList() {
        return list;
    }

    /** * @return resc list. */
    public List<RescInfo> getRescList() {
        return rescList;
    }

    /** * @return menu list. */
    public List<MenuInfo> getMenuList() {
        return menuList;
    }

    /** * @param id long. */
    public void setId(long id) {
        this.id = id;
    }

    /** * @param rescId long. */
    public void setRescId(long rescId) {
        this.rescId = rescId;
    }

    /** * @param menuId long. */
    public void setMenuId(long menuId) {
        this.menuId = menuId;
    }

    // ====================================================
    public void setStart(int start) {
        this.start = start;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    public void setSort(String sort) {
        this.sort = sort;
    }

    public void setDir(String dir) {
        this.dir = dir;
    }

    /**
     * 分页浏览记录.
     *
     * @throws Exception 异常
     */
    public void pagedQuery() throws Exception {
        // 分页
        int pageNo = (start / limit) + 1;

        QueryFilter filter = new QueryFilter();

        if (sort != null) {
            filter.addOrderBy(sort,dir);
        }

        PageList page = roleReps.getPageList(filter, pageNo, limit);

        JsonUtils.write(page,
            ServletActionContext.getResponse().getWriter(), getExcludes(),
            getDatePattern());
    }

    /**
     * 使用json绑定pojo，再将绑定的pojo返回.
     *
     * @return T entity
     * @throws Exception 解析时，可能抛出异常
     */
    protected RoleInfo bindObject() throws Exception {
        RoleInfo role = null;

        try {
            role = roleReps.getById(model.getId(),true);
        } catch (JSONException ex) {
            System.err.println(ex);
        }

        if (role == null) {
            role = model;
        } else {
            BeanUtil.copyProperties(model, role);
        }

        return role;
    }

    /**
     * 保存，新增或修改.
     *
     * @throws Exception 异常
     */
    public void save() throws Exception {
        RoleInfo entity = bindObject();

        roleReps.save(entity);
        ServletActionContext.getResponse().getWriter()
                            .print("{success:true}");
    }

    /**
     * 读取数据.
     *
     * @throws Exception 异常
     */
    public void loadData() throws Exception {
        RoleInfo entity = roleReps.getById(id,false);

        if (entity != null) {
            List<RoleInfo> list = new ArrayList<RoleInfo>();
            list.add(entity);
            JsonUtils.write(list,
                ServletActionContext.getResponse().getWriter(),
                getExcludes(), getDatePattern());
        }
    }

    /**
     * 删除记录.
     *
     * @throws Exception 异常
     */
    public void remove() throws Exception {
        for (String str : ids.split(",")) {
            try {
                long id = Long.parseLong(str);
                roleReps.deleteById(id);
            } catch (NumberFormatException ex) {
                continue;
            }
        }

        ServletActionContext.getResponse().getWriter()
                            .print("{success:true}");
    }

    public void setIds(String ids) {
        this.ids = ids;
    }

    /** * @return excludes. */
    public String[] getExcludes() {
        return new String[] {"roles", "users", "menus", "rescs"};
    }

    public String getDatePattern() {
        return "yyyy-MM-dd";
    }

    /**
     * 显示角色对应的资源列�?
     *
     * @throws Exception 异常
     */
    public void getRescs() throws Exception {
        RoleInfo role = roleReps.getById(roleId,false);

        List<RescInfo> rescs = facade.getRescList(null);

        if (role != null) {
            for (RescInfo resc : rescs) {
                if (role.getRescs().contains(resc)) {
                    resc.setAuthorized(true);
                }
            }
        }

        JsonUtils.write(rescs,
            ServletActionContext.getResponse().getWriter(), getExcludes(),
            getDatePattern());
    }

    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }

    public void setAuth(boolean auth) {
        this.auth = auth;
    }

    /**
     * 授权与撤消授�?
     *
     * @throws Exception 异常
     */
    public void authResc() throws Exception {
        RoleInfo role = roleReps.getById(roleId,false);
        RescInfo resc = facade.getRescById(rescId);

        if (auth) {
            if (!role.getRescs().contains(resc)) {
                role.getRescs().add(resc);
            }
        } else {
            if (role.getRescs().contains(resc)) {
                role.getRescs().remove(resc);
            }
        }

        roleReps.save(role);
        ServletActionContext.getResponse().getWriter()
                            .print("{success:true}");
    }

    /**
     * 显示指定角色下可显示的菜�?
     *
     * @throws Exception 写入writer的时候，抛出异常
     */
    public void getMenus() throws Exception {
        RoleInfo role = roleReps.getById(roleId,false);
        QueryFilter filter=new QueryFilter();
        filter.addQueryItem(new NullQueryItem("and","e.parent","is"))
        	.addOrderBy("e.theSort", "asc").addOrderBy("e.id", "desc");
        List<MenuInfo> list = facade.getMenuList(filter);

        // 因为只有两级菜单，所以这里只�?��写两个循环就可以判断哪些菜单被�?中了
        // 不�?虑多级情况，只从�?��接的角度考虑
        for (MenuInfo menu : list) {
            if (role.getMenus().contains(menu)) {
                menu.setChecked(true);

                for (MenuInfo subMenu : menu.getChildren()) {
                    if (role.getMenus().contains(subMenu)) {
                        subMenu.setChecked(true);
                    }
                }
            }
        }

        // 现在checkbox tree的问题是无法在js里设置根节点，必须在json里做�?��根节�?
        // 如果不设置根节点，getChecked()方法返回的只有第�?��树的数据，疑惑中�?
        // 为了他的限制，多写了下面这么多代码，真郁�?
        MenuInfo root = new MenuInfo();
        root.setId("0");
        root.setName("选择菜单");
        root.setChildren(new LinkedHashSet<MenuInfo>(list));
        root.setChecked(true);

        MenuInfo[] menus = new MenuInfo[] {root};

        JsonUtils.write(menus,
            ServletActionContext.getResponse().getWriter(), getExcludes(),
            getDatePattern());
    }

    /**
     * 选择角色对应的菜�?
     *
     * @throws Exception 写入response可能抛出异常吧？
     */
    public void selectMenu() throws Exception {
        RoleInfo role = roleReps.getById(roleId,true);

        if (role == null) {
            ServletActionContext.getResponse().getWriter()
                                .print("{success:false}");

            return;
        }

        role.getMenus().clear();

        for (String str : ids.split(",")) {
            try {
                long id = Long.parseLong(str);
                logger.info("{}", id);

                MenuInfo menu = facade.getMenuById(id);
                logger.info("{}", menu);

                if (menu != null) {
                    role.getMenus().add(menu);
                }
            } catch (Exception ex) {
                logger.info("", ex);
            }
        }

        roleReps.save(role);

        ServletActionContext.getResponse().getWriter()
                            .print("{success:true}");
    }
}
